/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - initial API and implementation
 */
package de.ipk_gatersleben.bit.bi.edal.primary_data.metadata;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;

import eu.medsea.util.MimeException;
import eu.medsea.util.MimeUtil;

/**
 * Data type to manage MIME types.
 * <p>
 * For MIME type definition, we make use of the {@link eu.medsea.util.MimeUtil}
 * package.
 * 
 * @author lange
 * @author arendd
 */
public class DataFormat extends UntypedData {

	private static final Map<Object, Object> EXT_MIME_TYPES;
	private String mimeType;

	/**
	 * generated serial ID
	 */
	private static final long serialVersionUID = 2100380388922795210L;
	/**
	 * The unknown format
	 */
	public static final DataFormat UNKNOWN_FORMAT;
	static {

		UNKNOWN_FORMAT = new DataFormat();

		EXT_MIME_TYPES = new Properties();
		try {
			((Properties) EXT_MIME_TYPES)
					.load(MimeUtil.class.getClassLoader().getResourceAsStream(
							"eu/medsea/util/mime-types.properties"));

		} catch (final IOException e) {
			// should never happen!!!
			e.printStackTrace();
		}

	}

	/**
	 * construct a DataFormat object with unknown type
	 */
	public DataFormat() {
		super();
		this.mimeType = MimeUtil.UNKNOWN_MIME_TYPE;
	}

	/**
	 * Constructor for DataFormat.
	 * 
	 * @param mimeType
	 *            the data format as MIME type in the format
	 * 
	 *            <pre>
	 * major / minor
	 * </pre>
	 *            <p>
	 *            E.g. unknown is:
	 * 
	 *            <pre>
	 * application / octet - stream
	 * </pre>
	 * @throws DataFormatException
	 *             if using a non valid MIME type.
	 */
	public DataFormat(final String mimeType) throws DataFormatException {
		/*
		 * Load the file extension mappings from the mime utils internal
		 * property file
		 */
		this();

		if (MimeUtil.isMimeTypeKnown(mimeType)) {
			this.mimeType = mimeType;
		} else {
			throw new DataFormatException(
					"unknown data format \""
							+ mimeType
							+ "\". please use a valid mime type in the format major/minor. E.g.\""
							+ MimeUtil.UNKNOWN_MIME_TYPE + "\"");
		}

	}

	/** {@inheritDoc} */
	@Override
	public int compareTo(final UntypedData datatype) {

		if (datatype instanceof DataFormat) {

			DataFormat dataFormat = (DataFormat) datatype;

			if (this.getMimeType().compareTo(dataFormat.getMimeType()) == 0) {
				return super.compareTo(datatype);
			} else {
				return this.getMimeType().compareTo(dataFormat.getMimeType());
			}
		} else {
			return super.compareTo(datatype);
		}
	}

	/**
	 * Guess the DataFormat for a given file
	 * 
	 * @param input
	 *            a {@link java.io.InputStream} object.
	 * @return the guessed DataFormat object; if format is not recognized then
	 *         the return {@link DataFormat#UNKNOWN_FORMAT}
	 */
	public static DataFormat guessDataFormat(final InputStream input) {
		try {

			final String mimes = MimeUtil.getMimeType(new BufferedInputStream(
					input));
			final String[] singleMimes = mimes.split(",");
			return new DataFormat(singleMimes[singleMimes.length - 1]);
		} catch (final MimeException e) {
			return DataFormat.UNKNOWN_FORMAT;
		} catch (final DataFormatException e) {
			// should never happen!!!
		}
		return DataFormat.UNKNOWN_FORMAT;
	}

	/**
	 * Getter for the field <code>mimeType</code>.
	 * 
	 * @return the mimeType
	 */
	public String getMimeType() {
		return mimeType;
	}

	/**
	 * Getter for valid MIME types.
	 * 
	 * @return a Collection<String> of all valid mime types
	 */
	@SuppressWarnings("unchecked")
	public Collection<String> getValidMimeTypes() {
		final Collection<String> ret = new HashSet<String>();
		final Collection<?> values = DataFormat.EXT_MIME_TYPES.values();
		for (final String mimes : (Collection<String>) values) {
			final String[] split = mimes.split(",");
			for (final String element : split) {
				ret.add(element);
			}
		}
		return ret;
	}

	/**
	 * Setter for the field <code>mimeType</code>.
	 * 
	 * @param mimeType
	 *            the mimeType to set
	 */
	public void setMimeType(String mimeType) {
		this.mimeType = mimeType;
	}

	/** {@inheritDoc} */
	@Override
	public String toString() {
		return this.mimeType;
	}
}
